#作业一
"""
什么是迭代器?什么是生成器?两者有什么区别?
"""

#迭代器
"""
概念上：迭代器可以用来表示一个数据流，提供了数据的惰性返回功能（只有我们主动去使用next方法调用，才会返回值)
实现上：实现了 __next__接口的对象
1.传统生命一个列表，里面的元素会立即写进内存当中，占用大量内存
迭代器可以一次只返回一个元素，占用的内存非常小，在读取大文件和大的数据集合的时候特别有用
"""

### 程序讲话
#两者实现的功能是一模一样的
# 通过 iter方法返回一个迭代器对象
l=list(range(10))
l2=iter(range(10))

#print(l,"\n")
#print("l2=",l2,"\n")

#通过next 方法主动获取迭代器中的值
"""
当 迭代器中没有值了以后，会抛出 StopIteration的异常，需要自行处理一下
"""
try:
 iter = iter(range(5))
 print(next(iter))
 print(next(iter))
 print(next(iter))
 print(next(iter))
 print(next(iter))
 print(next(iter))
except StopIteration:
    print("没 数据了 ")
#生成器
"""
生成器是一种特殊的迭代器，在迭代器惰性返回数据的基础上，提供了额外的功能，实现了程序的暂停
声明一个生成器
只要在函数体重有 yield 关键字，它既是一个生成器
yield 翻译为 让渡，我们可以简单理解为暂停并返回右边的值
"""

#让程序 代表 一切
def my_range_gen(n):
    for i in range(n):
        yield i*i
        print(f"current index:{i}")

try:
 my_range=my_range_gen(3)
 #print(my_range)
 print(next(my_range))
 print(next(my_range))
 print(next(my_range))
 print(next(my_range))
 print(next(my_range))
except StopIteration:
    print("no data")



#生成器和迭代器的区别？
"""
同样提供了惰性返回的功能，迭代器 侧重于 提供 数据的惰性返回功能，生成器侧重于 指令的惰性返回功能
"""


#协程
"""
协程的实现原理就是生成器的实现原理，在生成器的基础上又提供了传递值的功能
通过 send 方法 向生成器传递值，
对生成器进行 send 操作，一定要调用next 方法预激，使其停留在第一个 yield位置

"""

## 不懂就用代码 拉出来溜溜

def simple_coro(a):
    print("初始值a=",a)
    b=yield a
    print("传递值 b=",b)
    c=yield a+b
    print("传递值 c=",c)

try:
  coro=simple_coro(1)
  print(next(coro))
  print(coro.send(2))
  print(coro.send(3))
except StopIteration:
    print("no data")

## 用协程 来实现 计算平均数的函数
print("--------用协程 来实现 计算平均数的函数-----------")
def coro_avg():
    total=0
    length=0
    while True:
        try:
            value=yield  total/length
        except ZeroDivisionError:
            value=yield 0
        total+=value
        length+=1

my_avg=coro_avg()
print(next(my_avg))
print(my_avg.send(2))
print(my_avg.send(3))
print(my_avg.send(4))

# yield 和 yield from的区别
## yield from 用来驱动 子程序中的循环并返回最终值

print("--------------yield from----------")
def return_triple():
    while True:
        value=yield
        if value%2==0:
            return  value

triple_array=[]
def triple_recorder():
    while True:
        result=yield from return_triple()
        triple_array.append(result)

coro=triple_recorder()
next(coro)
for i in range(20):
    coro.send(i)
print(triple_array)


##异步
# asyncio(异步）
## Python3.4 引入的标准库，替代 yield from 实现协程异步IO，可以更好地实现异步程序
## 实现原理：自动维护了一个事件队列，然后循环访问 事件来完成异步的消息维护
import  asyncio
import  time
print("-----------asyncio(异步）-------")
"""
class Response:
    status_code=200

async def sim_request(index):
    print(f"模拟发送请求：Index:{index}")
    response=Response()
    ##模拟 网络延迟
    ## 当前是单线程 运行的，如果调用的是 time.sleep(1) 那么这个线程会被阻塞
    ## 当前线程被阻塞之后，不会让渡 CPU资源，异步的效率就不会体现

    await asyncio.sleep(1)
    print(f"requst index {index},response status_code:{response.status_code}")
    return response.status_code

#获取 消息队列
loop=asyncio.get_event_loop()

#包装任务
task_array=[]
for i in range(5):
    task_array.append(sim_request(i))

#循环访问事件 来完成异步的消息维护
#loop.run_until_complete(asyncio.wait(task_array))

#小技巧：：： 获取异步完成之后的所有返回值
result=loop.run_until_complete(asyncio.gather(*task_array))
print("----result--->,",result)
#关闭事件循环
loop.close()
"""



## 编写一个asyncio异步程序
# 自定义 异步函数
"""
print("---------自定义 异步函数----------")
async def hello():
    await asyncio.sleep(2)
    print("hello,world:%s"%time.time())

def run():
    for i in range(5):
        loop.run_until_complete(hello())

loop=asyncio.get_event_loop()
if __name__=='__main__':
    run()
"""

###扩展: 了解aiohttp异步请求网址
import aiohttp
print("-----------aiohttp异步请求网址-----------")
#目标协程
async def run():
    print("start get:")
    print(time.time())
    res=await  get()
    print("finish get：")
    print(time.time())

# 异步请求
async def get():
    url='htpp://baidu.com'
    async  with aiohttp.ClientSession() as session:
        async  with session.get(url) as response:
            # return await response.read()
            #假设 请求返回时间
            return  await asyncio.sleep(2)

async def creat_task(event_loop):
    while True:
        asyncio.run_coroutine_threadsafe(run(),event_loop)
        await  asyncio.sleep(1)# 设置定时时间

# 启动一个 loop
def start_loop(loop):
    asyncio.set_event_loop(loop)
    loop.run_forever()

from threading import  Thread
if __name__=='__main__':
    # 子线程 loop
    tread_loop=asyncio.new_event_loop()

    run_loop_thread=Thread(target=start_loop,args=(tread_loop,))
    run_loop_thread.start()

    main_loop=asyncio.new_event_loop()

    #在主线程loop里面
    main_loop.run_until_complete(creat_task(tread_loop))
    main_loop.close()